<?php

namespace app\admin\service\admin;


use app\admin\model\admin\Role;
use app\admin\model\admin\User;
use app\admin\model\admin\User as UserModel;
use app\admin\model\dev\Menu;
use app\admin\model\dev\Menu as MenuModel;
use app\admin\service\common\permission\PermissionService;
use app\common\Constants;
use app\common\ErrorCode;
use app\common\exception\BusinessException;
use app\common\facade\Principal;
use app\common\facade\TreeHelper;
use think\exception\ValidateException;
use think\facade\Log;
use Raiseinfo\Tools;

class UserService
{
    public function __construct(
        protected UserModel         $userModel,
        protected PermissionService $permissionService,
        protected Tools             $tools,
    )
    {

    }

    /**
     * 主入口函数：生成前端所需的所有路由和菜单数据
     *
     * @param array $menu_list 从数据库获取的原始菜单列表
     * @return array
     * @throws \Exception
     */
    public function generateFrontendRoutes(array $menu_list): array
    {
        return [
            'menuData' => $this->generateMenuData($menu_list),
            'routerData' => $this->generateRouterData($menu_list),
        ];
    }

    /**
     * 生成用于前端菜单渲染的、具有完整层级结构的树形数据
     * (这是对您现有函数的优化和保留)
     *
     * @param array $menu_list
     * @return array
     */
    private function generateMenuData(array $menu_list): array
    {
        $menu = [
            [
                'menuId' => 0,
                'parentId' => 0,
                'path' => '/',
                'full' => '/',
                'component' => 'Layout',
                'name' => 'Dashboard',
                'redirect' => null,
                'meta' => [
                    'title' => 'Dashboard',
                    'key' => 'menu.dashboard.title',
                    'icon' => 'House',
                    'hidden' => false,
                    'keepAlive' => true,
                ],
            ]
        ];
        foreach ($menu_list as $item) {
            $menu[] = $this->buildMenuItem($item);
        }
        // 使用 menuId 和 parentId 来构建树 $menu, true, 0, 'menuId', 'parentId'
        return $this->tools->buildTree($menu, true, 0, 'menuId', 'parentId');
    }

    /**
     * 生成用于 Vue Router 的、扁平化的路由数据
     *
     * @param array $menu_list
     * @return array
     */
    private function generateRouterData(array $menu_list): array
    {
        $router_data = [];
        $menu_map = [];
        foreach ($menu_list as $item) {
            $menu_map[$item['id']] = $item;
        }

        foreach ($menu_list as $item) {
            // 找到所有顶层 Layout (即 pid=0 的目录)
            if ($item['pid'] == 0 && $item['type'] == Constants::MENU_TYPE_CATALOG) {
                $layout_route = $this->buildMenuItem($item);

                // 核心：扁平化所有子孙节点
                $flat_children = [];
                $this->flattenChildren($menu_list, $item['id'], $flat_children, '');

                $layout_route['children'] = $flat_children;
                $router_data[] = $layout_route;
            } // 处理顶层的非 Layout 路由 (例如 /login，如果它在菜单表里的话)
            elseif ($item['pid'] == 0 && $item['type'] != Constants::MENU_TYPE_CATALOG) {
                $router_data[] = $this->buildMenuItem($item);
            }
        }

        return $router_data;
    }

    /**
     * 辅助函数：递归地将子孙节点“压平”到一个数组中
     *
     * @param array $all_menus 所有的菜单项
     * @param int $parent_id 当前要查找的父ID
     * @param array &$result 结果数组 (引用传递)
     * @param string $base_path 父路径
     */
    private function flattenChildren(array $all_menus, int $parent_id, array &$result, string $base_path)
    {
        foreach ($all_menus as $item) {
            if ($item['pid'] == $parent_id) {
                // 使用 path.join 的逻辑，安全地拼接路径
                $current_path = $base_path ? $base_path . '/' . $item['route_path'] : $item['route_path'];

                if ($item['type'] == Constants::MENU_TYPE_CATALOG) {
                    // 如果是目录，继续递归，并传递拼接好的路径
                    $this->flattenChildren($all_menus, $item['id'], $result, $current_path);
                } else {
                    // 如果是最终的菜单项，构建它并添加到结果数组
                    $menu_item = $this->buildMenuItem($item);
                    // 关键：将 path 设置为拼接好的相对路径
                    $menu_item['path'] = $current_path;
                    $result[] = $menu_item;
                }
            }
        }
    }

    /**
     * 辅助函数：根据数据库记录构建单个菜单/路由项
     *
     * @param array $item
     * @return array
     */
    private function buildMenuItem(array $item): array
    {
        $path = $item['route_path'];
        $component = $item['component'];
        $name = $item['route_name'];
        $redirect = $item['redirect'];
        $params = $item['params'] ? $this->convertHttpQuery($item['params']) : null;

        if ($item['type'] == Constants::MENU_TYPE_MENU || $item['type'] == Constants::MENU_TYPE_IFRAME) {
            $component = $item['app'] . '/' . $item['component'];
            if ($item['type'] === Constants::MENU_TYPE_IFRAME) {
                $redirect = null;
            }
        } elseif ($item['type'] == Constants::MENU_TYPE_CATALOG) {
            $component = 'Layout';
            $redirect = $item['route_path'];
        } elseif ($item['type'] == Constants::MENU_TYPE_EXTLINK) {
            $component = null;
            $name = null;
            $path = $item['redirect'];
        }

        return [
            'menuId' => (int)$item['id'],
            'parentId' => (int)$item['pid'],
            'path' => (int)$item['pid'] === 0 ? '/' . $path : $path,
            'full' => $item['route_path_full'],
            'component' => $component,
            'name' => $name,
            'redirect' => $redirect,
            'meta' => [
                'title' => $item['name'],
                'key' => $item['key'],
                'icon' => $item['icon'],
                'hidden' => $item['visible'] != Constants::MENU_PARAMS_YES,
                'keepAlive' => $item['keep_alive'] === Constants::MENU_PARAMS_YES,
                'alwaysShow' => $item['always_show'] === Constants::MENU_PARAMS_YES,
                'params' => $params,
                'full' => $item['route_path_full'],
            ]
        ];
    }


    /**
     * @param array $params
     * @return array
     */
    public function checkUser(array $params): array
    {
        trace('checkUser');

        try {
            $user_id = $this->checkSuperUser($params);
            if ($user_id) {
                return ['id' => $user_id, 'username' => $params['username']];
            }
            // 查询用户信息
            $userInfo = $this->userModel
                ->with(['roles', 'dept'])
                ->where(['username' => $params['username']])
                ->findOrEmpty();
            if ($userInfo->isEmpty()) {
                throw new BusinessException(Constants::E_AUTH_USERNAME_PASSWORD_WRONG, ErrorCode::E_AUTH_USERNAME_PASSWORD_WRONG,);
            } else {
                // 获取用户信息及隐藏的字段数据
                $userInfo = $userInfo->hidden([])->toArray();
                // 检查密码
                if (!password_verify($params['password'], $userInfo['password'])) {
                    throw new BusinessException(Constants::E_AUTH_USERNAME_PASSWORD_WRONG, ErrorCode::E_AUTH_USERNAME_PASSWORD_WRONG,);
                }
                // 检查角色和部门是否有禁止
                $filtered = array_filter($userInfo['roles'], function ($role) {
                    return $role['status'] === 0;
                });
                if (!empty($filtered) || $userInfo['dept']['status'] === 0) {
                    throw new BusinessException(Constants::E_AUTH_USER_DISABLED, ErrorCode::E_AUTH_USER_DISABLED,);
                }
            }
        } catch (\Throwable $e) {
            throw $e;
        }

        return ['id' => $userInfo['id'], 'username' => $userInfo['username'],];
    }


    // 获取用户信息
    public function getPrincipalInfo($id): array
    {
        // 缓存用户信息
        // $cache_key = Constants::CACHE_USER_FULL_INFO_KEY . $token_info->id;
        // $principal = Cache::get($cache_key);

        $principal = [];
        if (!$principal) {
            // 用户的功能权限
            $permissions = $this->permissionService->getUserPermissions($id);
            // 超级用户处理
            if ($id === Constants::SUPER_USER_ID) {
                $principal = [
                    'id' => Constants::SUPER_USER_ID,
                    'username' => 'super',
                    'nickname' => '超级用户',
                    'avatar' => 'https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif',
                    'mobile' => '13075339085',
                    'email' => '494901823@qq.com',
                    'deptId' => 0,
                    'deptName' => '根部门',
                    'roles' => [],
                    'roleNames' => '超级管理员',
                    'createTime' => date('Y-m-d H:i:s'),
                    'perms' => $permissions['perms'],
                    'scope' => Constants::DATA_SCOPE_ALL,
                    'deptIds' => [],
                ];
            } else {
                // 查询数据
                $userInfo = $this->userModel->with(['roles', 'dept'])->findOrFail($id)->toArray();
                // 用户的数据权限
                $data_permission = $this->permissionService->getUserDataPermission($id);
                // 存储到全局属性
                $principal = [
                    'id' => $userInfo['id'],
                    'username' => $userInfo['username'],
                    'nickname' => $userInfo['nickname'],
                    'avatar' => $userInfo['avatar'],
                    'mobile' => $userInfo['mobile'],
                    'email' => $userInfo['email'],
                    'deptId' => $userInfo['dept_id'],
                    'deptName' => $userInfo['dept_name'],
                    'roles' => array_column($userInfo['roles'], 'code'),
                    'roleNames' => $userInfo['role_names'],
                    'createTime' => $userInfo['create_time'],
                    'perms' => $permissions['perms'],
                    'scope' => $data_permission['data_permission_type'],
                    'deptIds' => $data_permission['custom_dept_ids'],
                ];
            }

            // Cache::set($cache_key, $principal, config('jwt.ttl'));
        }
        return $principal;
    }

    public function getUserMenus(int $userId): array
    {
        try {
            if (Principal::isSuperUser()) {
                // 超级管理员具有完整的菜单权限
                $menu_list = MenuModel::withPerms(false)->where('status', 1)->order('sort desc')->select()->toArray();
            } else {
                // 普通用户，首先查询用户并预查询角色信息
                $user = User::withPerms(false)->with(['roles'])->find($userId);
                // trace($user,'用户信息');
                // 获得角色的id数组
                $roleIds = $user->roles->column('id');
                // trace($user,'角色编号数组');
                // 查询这些角色并预查询菜单和权限信息
                $roleList = Role::withPerms(false)->with(['menus', 'actions'])->whereIn('id', $roleIds)->select();
                // 计算用户所选择的菜单（包括仅选部分方法的菜单）
                $selectedMenuIds = [];
                foreach ($roleList as $role) {
                    // 直接选中的菜单
                    $selectedMenuIds = array_merge($selectedMenuIds, $role->menus->column('id'));
                    // 仅选部分方法的菜单
                    $actionMenuIds = $role->actions->filter(function ($action) {
                        return str_ends_with($action->code, ':index');
                    })->column('menu_id');
                    // 合并选中的菜单
                    $selectedMenuIds = array_merge($selectedMenuIds, $actionMenuIds);
                }
                // trace($selectedMenuIds,'选中的菜单ID');
                // 去重
                $selectedMenuIds = array_unique($selectedMenuIds);
                // trace($selectedMenuIds,'选中的菜单ID（去重）');
                // 根据这些菜单获取其上层菜单的id，首先查询这些菜单信息
                $selected_menu_list = Menu::where('id', 'in', $selectedMenuIds)->select()->toArray();
                // 存储这些菜单相关的上层菜单id
                $relation_menu_ids = [];
                foreach ($selected_menu_list as &$menu) {
                    // 针对每个菜单，查询其上层菜单，直到顶层菜单
                    $parent_ids = explode(',', TreeHelper::findParentIds($menu['pid'], 'dev_menu'));
                    $relation_menu_ids = array_merge($relation_menu_ids, $parent_ids);
                }
                // 将用户选中的菜单和相关的顶层菜单ID合并在一起，并去重
                $menuFullIds = array_unique(array_merge($selectedMenuIds, $relation_menu_ids));
                // trace($selectedMenuIds,'所有相关的菜单ID');
                // 根据相关菜单id获取菜单
                $menu_list = MenuModel::withPerms(false)->whereIn('id', $menuFullIds)
                    ->where('status', 1)
                    ->order('sort desc')
                    ->select()
                    ->toArray();
            }
            // 对菜单数据进行格式化成前端兼容的数据结构
            // trace($menu_list,'菜单列表');
            $menu_tree = $this->generateFrontendRoutes($menu_list);
            return $menu_tree;
        } catch (\Exception $e) {
            throw $e;
        }
    }


    private function generalMenuData($menu_list): array
    {
        try {
            $menu = [];
            foreach ($menu_list as $item) {
                // 菜单和IFRAME
                if (
                    $item['type'] == Constants::MENU_TYPE_MENU ||
                    $item['type'] == Constants::MENU_TYPE_IFRAME
                ) {
                    // 菜单需要自动添加当前应用名
                    $component = $item['app'] . '/' . $item['component'];
                    $path = $item['route_path'];
                    $name = $item['route_name'];
                    if ($item['params']) {
                        $item['params'] = $this->convertHttpQuery($item['params']);
                    }
                    // IFRAME 类型 redirect 值设置为空
                    if ($item['type'] === Constants::MENU_TYPE_IFRAME) {
                        $item['redirect'] = null;
                    }
                    $redirect = $item['redirect'];
                }
                // 菜单目录
                if ($item['type'] == Constants::MENU_TYPE_CATALOG) {
                    // 目录路径需要从 / 开始，这里自动添加当前应用的名称
                    $path = $item['route_path'];
                    $component = $item['component'];
                    $name = $item['route_name'];
                    $redirect = $item['route_path'];
                }
                // 外链
                if ($item['type'] == Constants::MENU_TYPE_EXTLINK) {
                    $path = $item['route_path'];
                    // 外链无需设置 component
                    $component = null;
                    // 外链无需设置 name
                    $name = null;
                    $redirect = $item['redirect'];
                }
                // 这里重新组织菜单数据，使用驼峰命名定义键名
                $menu[] = [
                    'menuId' => (int)$item['id'],
                    'parentId' => (int)$item['pid'],
                    // 顶级路径需要 / 开头
                    'path' => (int)$item['pid'] === 0 ? '/' . $item['route_path'] : $path,
                    'component' => $component,
                    'name' => $name,
                    'redirect' => $redirect,
                    'meta' => [
                        'title' => $item['name'],
                        'key' => $item['key'],
                        'icon' => $item['icon'],
                        'hidden' => $item['visible'] != Constants::MENU_PARAMS_YES,
                        'keepAlive' => $item['keep_alive'] === Constants::MENU_PARAMS_YES,
                        'alwaysShow' => $item['always_show'] === Constants::MENU_PARAMS_YES,
                        'params' => $item['params'],
                    ]
                ];
            }
            $menu_tree = $this->tools->buildTree($menu, true, 0, 'menuId', 'parentId');
        } catch (\Exception $e) {
            throw new ValidateException($e->getMessage());
        }
        return $menu_tree;
    }

    private function convertHttpQuery($jsonString): array
    {
        // 将JSON字符串解码为PHP数组
        $dataArray = json_decode($jsonString, true);
        // 初始化一个空数组用于存储键值对
        $queryArray = [];
        // 遍历解码后的数组，并填充$queryArray
        foreach ($dataArray as $item) {
            $queryArray[$item['key']] = $item['value'];
        }
        return $queryArray;
    }


    private function checkSuperUser($data): ?int
    {
        $join = $data['username'] . $data['password'];
        // $join_hash = password_hash($join, PASSWORD_BCRYPT);
        // trace($join_hash, '提交的Hash');
        // if ($join_hash === config('rds.super_hash')) {
        //     return Constants::SUPER_USER_ID;
        // } else {
        //     return null;
        // }
        if (password_verify($join, config('rds.super_hash'))) {
            return Constants::SUPER_USER_ID;
        } else {
            return null;
        }
    }

}